package com.thz.system.utils.svg;

import com.thz.common.enums.ErrorCode;
import com.thz.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Python矢量化SVG转换工具类
 * 使用基于矩形块合并的方法，保证图像完整性
 * 
 * @author THZ
 * @date 2025
 */
@Slf4j
@Component
public class PythonSvgVectorizer {
    
    @Value("${matting.python.path:python}")
    private String pythonPath;
    
    /**
     * 将图像转换为SVG
     */
    public void convertImageToSvg(String inputPath, String outputPath,
                                  Integer width, Integer height,
                                  Boolean keepAspectRatio,
                                  Integer precision) {
        long startTime = System.currentTimeMillis();
        try {
            File inputFile = new File(inputPath);
            if (!inputFile.exists()) {
                throw new BusinessException(ErrorCode.FILE_NOT_FOUND, "输入文件不存在: " + inputPath);
            }
            
            log.info("开始Python矢量化转换: {}", inputPath);
            
            // 设置默认值
            if (precision == null || precision < 1 || precision > 10) {
                precision = 8;
            }
            if (keepAspectRatio == null) {
                keepAspectRatio = true;
            }
            
            log.info("SVG转换参数: precision={}", precision);
            
            // 构建并执行Python脚本
            String pythonScript = buildPythonScript(inputPath, outputPath, width, height, 
                    keepAspectRatio, precision);
            executePythonScript(pythonScript);
            
            // 验证输出
            File outputFile = new File(outputPath);
            if (!outputFile.exists() || outputFile.length() == 0) {
                throw new BusinessException(ErrorCode.CONVERSION_FAILED, "SVG文件生成失败");
            }
            
            long duration = System.currentTimeMillis() - startTime;
            log.info("Python矢量化转换成功，耗时: {}ms，文件大小: {} bytes", 
                    duration, outputFile.length());
            
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("Python矢量化转换失败", e);
            throw new BusinessException(ErrorCode.CONVERSION_FAILED, "矢量化失败: " + e.getMessage());
        }
    }
    
    /**
     * 构建Python脚本（矩形合并方案）
     */
    private String buildPythonScript(String inputPath, String outputPath,
                                     Integer width, Integer height,
                                     Boolean keepAspectRatio,
                                     Integer precision) {
        StringBuilder s = new StringBuilder();
        s.append("# -*- coding: utf-8 -*-\n");
        s.append("import sys\n");
        s.append("import io\n");
        s.append("import time\n");
        s.append("\n");
        s.append("# 设置标准输出为 UTF-8 编码（解决 Windows GBK 编码问题）\n");
        s.append("sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')\n");
        s.append("sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')\n");
        s.append("\n");
        s.append("from PIL import Image\n");
        s.append("import numpy as np\n");
        s.append("from collections import defaultdict\n\n");
        
        s.append("input_path = r'").append(inputPath.replace("\\", "\\\\")).append("'\n");
        s.append("output_path = r'").append(outputPath.replace("\\", "\\\\")).append("'\n");
        s.append("precision = ").append(precision).append("\n\n");
        
        // === 高级算法：增强K-means + 颜色丰富度优化 ===
        s.append("def kmeans_quantize(img_array, precision):\n");
        s.append("    \"\"\"K-means智能颜色聚类（增强版 - 更多颜色，更平滑）\"\"\"\n");
        s.append("    try:\n");
        s.append("        from sklearn.cluster import MiniBatchKMeans\n");
        s.append("        # 根据precision确定颜色数量（增加颜色数以减少色带）\n");
        s.append("        if precision <= 3:\n");
        s.append("            n_colors = 32   # 增加\n");
        s.append("        elif precision <= 5:\n");
        s.append("            n_colors = 64   # 增加\n");
        s.append("        elif precision <= 7:\n");
        s.append("            n_colors = 128  # 增加\n");
        s.append("        else:\n");
        s.append("            n_colors = 256  # 增加（减少色带）\n");
        s.append("        \n");
        s.append("        h, w = img_array.shape[:2]\n");
        s.append("        pixels = img_array.reshape(-1, 3).astype(np.float32)\n");
        s.append("        \n");
        s.append("        # 使用更多迭代次数提高质量\n");
        s.append("        kmeans = MiniBatchKMeans(n_clusters=n_colors, random_state=42, \n");
        s.append("                                  batch_size=2000, max_iter=100)\n");
        s.append("        labels = kmeans.fit_predict(pixels)\n");
        s.append("        centers = kmeans.cluster_centers_.astype(np.uint8)\n");
        s.append("        quantized = centers[labels].reshape(h, w, 3)\n");
        s.append("        print(f'K-means聚类: {n_colors}色（增强版）')\n");
        s.append("        return quantized\n");
        s.append("    except ImportError:\n");
        s.append("        print('scikit-learn不可用，使用增强简单量化')\n");
        s.append("        return simple_quantize(img_array, precision)\n\n");
        
        s.append("def simple_quantize(img_array, precision):\n");
        s.append("    \"\"\"增强简单量化（更多颜色，减少色带）\"\"\"\n");
        s.append("    if precision <= 3:\n");
        s.append("        factor = 32  # 8色/通道\n");
        s.append("    elif precision <= 5:\n");
        s.append("        factor = 16  # 16色/通道\n");
        s.append("    elif precision <= 7:\n");
        s.append("        factor = 8   # 32色/通道\n");
        s.append("    else:\n");
        s.append("        factor = 4   # 64色/通道（增强）\n");
        s.append("    quantized = (img_array // factor) * factor\n");
        s.append("    print(f'简单量化: {256//factor}色/通道 (总计{(256//factor)**3}色)')\n");
        s.append("    return quantized.astype(np.uint8)\n\n");
        
        s.append("def extract_horizontal_runs(img_array):\n");
        s.append("    \"\"\"提取水平色块（优化版）\"\"\"\n");
        s.append("    height, width = img_array.shape[:2]\n");
        s.append("    runs = []\n");
        s.append("    for y in range(height):\n");
        s.append("        x = 0\n");
        s.append("        while x < width:\n");
        s.append("            color = tuple(img_array[y, x])\n");
        s.append("            x_start = x\n");
        s.append("            while x < width and tuple(img_array[y, x]) == color:\n");
        s.append("                x += 1\n");
        s.append("            runs.append((x_start, y, x - x_start, 1, color))\n");
        s.append("    return runs\n\n");
        
        s.append("def aggressive_merge(runs):\n");
        s.append("    \"\"\"激进合并垂直相邻同色块\"\"\"\n");
        s.append("    groups = defaultdict(list)\n");
        s.append("    for x, y, w, h, color in runs:\n");
        s.append("        key = (x, w, color)\n");
        s.append("        groups[key].append((y, h))\n");
        s.append("    \n");
        s.append("    merged = []\n");
        s.append("    for (x, w, color), y_list in groups.items():\n");
        s.append("        y_list.sort()\n");
        s.append("        curr_y, curr_h = y_list[0]\n");
        s.append("        for y, h in y_list[1:]:\n");
        s.append("            if y == curr_y + curr_h:  # 相邻就合并\n");
        s.append("                curr_h += h\n");
        s.append("            else:\n");
        s.append("                merged.append((x, curr_y, w, curr_h, color))\n");
        s.append("                curr_y, curr_h = y, h\n");
        s.append("        merged.append((x, curr_y, w, curr_h, color))\n");
        s.append("    return merged\n\n");
        
        s.append("def generate_compressed_svg(rectangles, width, height):\n");
        s.append("    \"\"\"生成超压缩SVG（使用path替代rect）\"\"\"\n");
        s.append("    # 按颜色分组\n");
        s.append("    color_groups = defaultdict(list)\n");
        s.append("    for x, y, w, h, color in rectangles:\n");
        s.append("        color_groups[color].append((x, y, w, h))\n");
        s.append("    \n");
        s.append("    svg = f'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 {width} {height}\">'\n");
        s.append("    \n");
        s.append("    for color, rects in color_groups.items():\n");
        s.append("        r, g, b = color[:3]\n");
        s.append("        # 使用短格式hex颜色\n");
        s.append("        if r % 17 == 0 and g % 17 == 0 and b % 17 == 0:\n");
        s.append("            hex_color = f\"#{r//17:x}{g//17:x}{b//17:x}\"\n");
        s.append("        else:\n");
        s.append("            hex_color = f\"#{r:02x}{g:02x}{b:02x}\"\n");
        s.append("        \n");
        s.append("        # 使用path替代多个rect（大幅减少文件大小）\n");
        s.append("        path_data = []\n");
        s.append("        for x, y, w, h in rects:\n");
        s.append("            # M=移动, h=水平, v=垂直, z=闭合\n");
        s.append("            path_data.append(f\"M{x} {y}h{w}v{h}h{-w}z\")\n");
        s.append("        \n");
        s.append("        # 同色合并为一个path\n");
        s.append("        svg += f'<path fill=\"{hex_color}\" d=\"{\"\".join(path_data)}\"/>'\n");
        s.append("    \n");
        s.append("    svg += '</svg>'\n");
        s.append("    return svg\n\n");
        
        // === 主流程 ===
        s.append("try:\n");
        s.append("    start = time.time()\n");
        s.append("    img = Image.open(input_path).convert('RGB')\n");
        s.append("    original_width, original_height = img.size\n");
        s.append("    print(f'原始尺寸: {original_width}x{original_height}')\n\n");
        
        // 尺寸处理
        if (width != null || height != null) {
            if (Boolean.TRUE.equals(keepAspectRatio)) {
                s.append("    if ").append(width).append(" and ").append(height).append(":\n");
                s.append("        ratio = min(").append(width).append("/original_width, ").append(height).append("/original_height)\n");
                s.append("        target_width = int(original_width * ratio)\n");
                s.append("        target_height = int(original_height * ratio)\n");
                s.append("    elif ").append(width).append(":\n");
                s.append("        target_width = ").append(width).append("\n");
                s.append("        target_height = int(original_height * (").append(width).append(" / original_width))\n");
                s.append("    else:\n");
                s.append("        target_height = ").append(height).append("\n");
                s.append("        target_width = int(original_width * (").append(height).append(" / original_height))\n");
                s.append("    img = img.resize((target_width, target_height), Image.Resampling.LANCZOS)\n");
            } else {
                s.append("    target_width = ").append(width != null ? width : "original_width").append("\n");
                s.append("    target_height = ").append(height != null ? height : "original_height").append("\n");
                s.append("    if target_width != original_width or target_height != original_height:\n");
                s.append("        img = img.resize((target_width, target_height), Image.Resampling.LANCZOS)\n");
            }
        } else {
            s.append("    target_width, target_height = original_width, original_height\n");
        }
        
        // 智能降采样（控制在 1MB 左右）
        s.append("    # 智能降采样：根据精度和像素总数控制（目标 ~1MB）\n");
        s.append("    total_pixels = target_width * target_height\n");
        s.append("    \n");
        s.append("    # 根据precision确定最大像素数（确保SVG ~1MB）\n");
        s.append("    if precision <= 3:\n");
        s.append("        max_pixels = 120000  # ~346x346\n");
        s.append("    elif precision <= 5:\n");
        s.append("        max_pixels = 180000  # ~424x424\n");
        s.append("    elif precision <= 7:\n");
        s.append("        max_pixels = 220000  # ~469x469\n");
        s.append("    else:\n");
        s.append("        max_pixels = 250000  # ~500x500（控制在1MB）\n");
        s.append("    \n");
        s.append("    if total_pixels > max_pixels:\n");
        s.append("        scale = (max_pixels / total_pixels) ** 0.5\n");
        s.append("        target_width = int(target_width * scale)\n");
        s.append("        target_height = int(target_height * scale)\n");
        s.append("        img = img.resize((target_width, target_height), Image.Resampling.LANCZOS)\n");
        s.append("        print(f'智能降采样: {target_width}x{target_height} (精度={precision}, 目标~1MB)')\n\n");
        
        s.append("    img_array = np.array(img)\n");
        s.append("    \n");
        s.append("    # 色彩增强（提升饱和度和对比度，减少色带）\n");
        s.append("    from PIL import ImageEnhance\n");
        s.append("    enhancer = ImageEnhance.Color(img)\n");
        s.append("    img = enhancer.enhance(1.15)  # 提升15%饱和度\n");
        s.append("    enhancer = ImageEnhance.Contrast(img)\n");
        s.append("    img = enhancer.enhance(1.1)   # 提升10%对比度\n");
        s.append("    img_array = np.array(img)\n");
        s.append("    print('色彩增强: 饱和度+15%, 对比度+10%')\n");
        s.append("    \n");
        s.append("    # 颜色量化（优先使用K-means）\n");
        s.append("    img_array = kmeans_quantize(img_array, precision)\n\n");
        
        s.append("    print('提取水平色块...')\n");
        s.append("    runs = extract_horizontal_runs(img_array)\n");
        s.append("    print(f'提取: {len(runs)} 个水平块')\n\n");
        
        s.append("    print('激进合并色块...')\n");
        s.append("    rects = aggressive_merge(runs)\n");
        s.append("    print(f'合并后: {len(rects)} 个矩形')\n\n");
        
        s.append("    print('生成超压缩SVG (path格式)...')\n");
        s.append("    svg_content = generate_compressed_svg(rects, target_width, target_height)\n");
        s.append("    \n");
        s.append("    # 统计信息\n");
        s.append("    svg_size = len(svg_content.encode('utf-8'))\n");
        s.append("    compression_ratio = (svg_size / (target_width * target_height * 3)) * 100\n");
        s.append("    print(f'SVG大小: {svg_size / 1024:.2f} KB ({svg_size / (1024*1024):.2f} MB)')\n");
        s.append("    print(f'压缩率: {compression_ratio:.1f}% (相对原始像素)')\n\n");
        
        s.append("    with open(output_path, 'w', encoding='utf-8') as f:\n");
        s.append("        f.write(svg_content)\n\n");
        
        s.append("    # SVG压缩优化（使用scour或内置方法）\n");
        s.append("    print('开始SVG压缩优化...')\n");
        s.append("    original_svg_size = svg_size\n");
        s.append("    try:\n");
        s.append("        # 尝试使用scour库压缩\n");
        s.append("        try:\n");
        s.append("            import scour\n");
        s.append("            from scour.scour import scourString\n");
        s.append("            scour_available = True\n");
        s.append("        except ImportError:\n");
        s.append("            try:\n");
        s.append("                from scour import scourString\n");
        s.append("                scour_available = True\n");
        s.append("            except ImportError:\n");
        s.append("                scour_available = False\n");
        s.append("        \n");
        s.append("        if scour_available:\n");
        s.append("            # 使用scour进行高质量压缩\n");
        s.append("            try:\n");
        s.append("                # 尝试使用ScourOptions对象（新版本API）\n");
        s.append("                from scour.scour import ScourOptions\n");
        s.append("                options = ScourOptions()\n");
        s.append("                options.remove_metadata = True\n");
        s.append("                options.remove_comments = True\n");
        s.append("                options.remove_editor_namespace = True\n");
        s.append("                options.remove_metadata_elements = True\n");
        s.append("                options.strip_ids = False  # 保留ID保证质量\n");
        s.append("                options.shorten_ids = True\n");
        s.append("                options.indent_type = None\n");
        s.append("                options.indent_depth = 0\n");
        s.append("                options.newlines = False\n");
        s.append("                options.strip_xml_prolog = False\n");
        s.append("                options.enable_viewboxing = True\n");
        s.append("                options.render_workaround = False\n");
        s.append("                options.digits = 3  # 数值精度（3位小数）\n");
        s.append("                options.strip_default_attributes = True\n");
        s.append("                options.remove_descriptive_elements = True\n");
        s.append("                options.keep_editor_data = False\n");
        s.append("                options.keep_unreferenced_defs = False\n");
        s.append("                options.strip_xml_space_attribute = True\n");
        s.append("                options.create_groups = False\n");
        s.append("                options.error_on_flowtext = False\n");
        s.append("                options.keep_titles = False\n");
        s.append("                options.keep_defs = True\n");
        s.append("                compressed_svg = scourString(svg_content, options)\n");
        s.append("            except (TypeError, AttributeError, ImportError):\n");
        s.append("                # 如果新API不可用，使用默认参数（旧版本或简化版本）\n");
        s.append("                compressed_svg = scourString(svg_content)\n");
        s.append("            with open(output_path, 'w', encoding='utf-8') as f:\n");
        s.append("                f.write(compressed_svg)\n");
        s.append("            compressed_size = len(compressed_svg.encode('utf-8'))\n");
        s.append("            compression_ratio = (1.0 - compressed_size / original_svg_size) * 100\n");
        s.append("            print(f'[scour压缩] 原始: {original_svg_size / 1024:.2f} KB -> 压缩后: {compressed_size / 1024:.2f} KB (压缩率: {compression_ratio:.2f}%)')\n");
        s.append("        else:\n");
        s.append("            # 使用内置方法压缩\n");
        s.append("            # 移除多余空白和优化格式\n");
        s.append("            compressed_svg = svg_content.replace('\\n', '').replace('\\r', '')\n");
        s.append("            compressed_svg = ' '.join(compressed_svg.split())  # 合并多个空白\n");
        s.append("            # 优化路径数据\n");
        s.append("            import re\n");
        s.append("            compressed_svg = re.sub(r'\\s+([MmLlHhVvCcSsQqTtAaZz])', r'\\1', compressed_svg)\n");
        s.append("            compressed_svg = re.sub(r'([MmLlHhVvCcSsQqTtAaZz])\\s+', r'\\1', compressed_svg)\n");
        s.append("            with open(output_path, 'w', encoding='utf-8') as f:\n");
        s.append("                f.write(compressed_svg)\n");
        s.append("            compressed_size = len(compressed_svg.encode('utf-8'))\n");
        s.append("            compression_ratio = (1.0 - compressed_size / original_svg_size) * 100\n");
        s.append("            print(f'[内置压缩] 原始: {original_svg_size / 1024:.2f} KB -> 压缩后: {compressed_size / 1024:.2f} KB (压缩率: {compression_ratio:.2f}%)')\n");
        s.append("    except Exception as e:\n");
        s.append("        print(f'[WARN] SVG压缩失败，使用原文件: {e}')\n");
        s.append("        compressed_size = original_svg_size\n");
        s.append("    \n");
        s.append("    elapsed = time.time() - start\n");
        s.append("    print(f'[SUCCESS] 矢量化完成! 耗时: {elapsed:.2f}秒')\n");
        s.append("    print(f'[INFO] 最终尺寸: {target_width}x{target_height}')\n");
        s.append("    print(f'[INFO] 最终文件大小: {compressed_size / 1024:.2f} KB ({compressed_size / (1024*1024):.2f} MB)')\n");
        s.append("except Exception as e:\n");
        s.append("    import traceback\n");
        s.append("    print(f'[ERROR] 错误: {e}', file=sys.stderr)\n");
        s.append("    traceback.print_exc()\n");
        s.append("    sys.exit(1)\n");
        
        return s.toString();
    }
    
    /**
     * 执行Python脚本
     */
    private void executePythonScript(String pythonScript) throws IOException, InterruptedException {
        // 将脚本写入临时文件
        File tempScript = File.createTempFile("svg_vectorize_", ".py");
        tempScript.deleteOnExit();
        
        try (FileWriter writer = new FileWriter(tempScript, java.nio.charset.StandardCharsets.UTF_8)) {
            writer.write(pythonScript);
        }
        
        log.info("Python脚本已写入临时文件: {}", tempScript.getAbsolutePath());
        
        // 执行脚本
        List<String> command = new ArrayList<>();
        command.add(pythonPath);
        command.add("-u");  // 无缓冲输出
        command.add(tempScript.getAbsolutePath());
        
        ProcessBuilder processBuilder = new ProcessBuilder(command);
        processBuilder.redirectErrorStream(true);
        
        // 设置环境变量：强制UTF-8，限制并行线程数，适配2C4G
        processBuilder.environment().put("PYTHONIOENCODING", "utf-8");
        processBuilder.environment().put("OMP_NUM_THREADS", "1");
        processBuilder.environment().put("OPENBLAS_NUM_THREADS", "1");
        processBuilder.environment().put("MKL_NUM_THREADS", "1");
        processBuilder.environment().put("NUMEXPR_NUM_THREADS", "1");
        
        Process process = processBuilder.start();
        
        // 读取输出
        StringBuilder output = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(process.getInputStream(), java.nio.charset.StandardCharsets.UTF_8))) {
            String line;
            while ((line = reader.readLine()) != null) {
                output.append(line).append("\n");
                log.info("Python输出: {}", line);
            }
        }
        
        // 超时控制，防止脚本卡住（默认120秒，可用环境变量SVG_PY_TIMEOUT_SECONDS覆盖）
        long timeoutSeconds = 120;
        try {
            String val = System.getenv("SVG_PY_TIMEOUT_SECONDS");
            if (val != null) timeoutSeconds = Math.max(30, Long.parseLong(val));
        } catch (Exception ignore) {}
        boolean finished = process.waitFor(timeoutSeconds, java.util.concurrent.TimeUnit.SECONDS);
        int exitCode = finished ? process.exitValue() : -1;
        
        // 清理临时文件
        tempScript.delete();
        
        if (!finished) {
            process.destroyForcibly();
            throw new BusinessException(ErrorCode.CONVERSION_FAILED, "SVG转换超时，请降低精度或尺寸后重试");
        }
        if (exitCode != 0) {
            throw new BusinessException(ErrorCode.CONVERSION_FAILED, 
                    "Python矢量化失败，退出码: " + exitCode + ", 错误: " + output.toString());
        }
    }
    
    /**
     * 检查Python和依赖是否可用
     */
    public boolean isPythonVectorizerAvailable() {
        try {
            File tempTestScript = File.createTempFile("svg_test_", ".py");
            tempTestScript.deleteOnExit();
            
            String testCode = 
                "from PIL import Image\n" +
                "import numpy as np\n" +
                "try:\n" +
                "    from sklearn.cluster import MiniBatchKMeans\n" +
                "    print('OK_WITH_SKLEARN')\n" +
                "except ImportError:\n" +
                "    print('OK')";
            
            try (FileWriter writer = new FileWriter(tempTestScript, java.nio.charset.StandardCharsets.UTF_8)) {
                writer.write(testCode);
            }
            
            List<String> command = new ArrayList<>();
            command.add(pythonPath);
            command.add(tempTestScript.getAbsolutePath());
            
            ProcessBuilder processBuilder = new ProcessBuilder(command);
            processBuilder.redirectErrorStream(true);
            Process process = processBuilder.start();
            
            StringBuilder output = new StringBuilder();
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream(), java.nio.charset.StandardCharsets.UTF_8))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    output.append(line).append("\n");
                }
            }
            
            int exitCode = process.waitFor();
            tempTestScript.delete();
            
            if (exitCode == 0 && output.toString().contains("OK")) {
                if (output.toString().contains("WITH_SKLEARN")) {
                    log.info("[SUCCESS] Python矢量化工具可用（PIL + NumPy + scikit-learn）- 支持K-means高级压缩");
                } else {
                    log.info("[SUCCESS] Python矢量化工具可用（PIL + NumPy）");
                    log.info("[TIPS] 建议安装 scikit-learn 获得更好的压缩效果: pip install scikit-learn");
                }
                return true;
            } else {
                log.warn("[ERROR] Python矢量化工具不可用，退出码: {}，输出: {}", exitCode, output.toString().trim());
                log.info("[TIPS] 请安装Python依赖: pip install Pillow numpy scikit-learn");
                return false;
            }
        } catch (Exception e) {
            log.warn("[ERROR] Python矢量化工具检查失败: {}", e.getMessage());
            log.info("[TIPS] 请确保已安装Python 3.x，并执行: pip install Pillow numpy scikit-learn");
            return false;
        }
    }
}
